﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PoolGame2.Assets;
using PoolGame2.Physics;

namespace PoolGame2.Game
{
    public class GameObject : GameComponent
    {
        protected List<GameObject> childrenObjects = null;
        protected PhysicsObject physicsObject = null;
        protected ModelObject modelObject = null;

        protected Vector3 position = Vector3.Zero;
        protected Vector3 rotation = Vector3.Zero;
        protected Vector3 velocity = Vector3.Zero;
        protected float scale = 1.0f;

        // Name so we can differentiate between game objects
        protected String name = null;

        protected bool visible = true;

        public GameObject(PoolGame game)
            : base(game)
        {
            childrenObjects = new List<GameObject>(5);
        }

        public GameObject(PoolGame game, ModelObject modelO, PhysicsObject physicsO, String newName)
            : base(game)
        {
            childrenObjects = new List<GameObject>(5);
            this.modelObject = modelO;
            this.physicsObject = physicsO;
            this.name = newName;
        }

        public String getName()
        {
            return this.name;
        }

        public void setModel(ModelObject obj)
        {
            modelObject = obj;
        }

		public override void Update(GameTime gametime)
        {
            foreach (GameObject child in childrenObjects)
            {
                child.Update(gametime);
            }
        }
        
        public virtual void Draw(GameTime gametime)
        {
            if (visible == false)
                return;

            if (modelObject != null)
            {
                Model model = modelObject.getModel();
                // Copy any parent transforms.
                Matrix[] transforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(transforms);

                Matrix worldMatrix = getWorldMatrix();

                if (this.getPhysicsObject() != null)
                {
                    PhysicsObject physicsObject = this.getPhysicsObject();
                    if (!physicsObject.getVisible())
                        return;
                    Vector3 pos = physicsObject.getPosition();
                    
                    worldMatrix = Matrix.Identity;

                    if (physicsObject is Ball)
                        worldMatrix *= ((Ball)physicsObject).getOrientation();

                    worldMatrix *= Matrix.CreateTranslation(pos);
                    
                }

                PoolGame game = (PoolGame)this.Game;
                foreach (ModelMesh mesh in modelObject.getModel().Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();
                        effect.PreferPerPixelLighting = true;
                        effect.DirectionalLight0.Direction = Vector3.Down;
                        effect.DirectionalLight0.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                        effect.DirectionalLight0.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
                        effect.DirectionalLight0.Enabled = true;
                        effect.DirectionalLight1.Direction = Vector3.Left;
                        effect.DirectionalLight1.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                        effect.DirectionalLight1.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
                        effect.DirectionalLight1.Enabled = true;
                        effect.SpecularPower = 50;
                        effect.World = transforms[mesh.ParentBone.Index] * worldMatrix;
                        effect.Projection = game.gameManager.GetCameraManager().GetCamera().projectionMatrix;
                        effect.View = game.gameManager.GetCameraManager().GetCamera().viewMatrix;
                    }
                    mesh.Draw();
                }
            }

            foreach( GameObject child in childrenObjects)
            {
                child.Draw(gametime);
            }
        }

        public virtual Vector3 getPosition()
        {
            if (physicsObject != null)
                return physicsObject.getPosition();

            return position;
        }

        public virtual Vector3 getRotation()
        {
            if (physicsObject != null)
                return physicsObject.getRotation();

            return rotation;
        }

        public virtual Vector3 getVelocity()
        {
            if (physicsObject != null)
                return physicsObject.getVelocity();

            return velocity;
        }

        public virtual Matrix getWorldMatrix()
        {
            return Matrix.CreateFromYawPitchRoll( rotation.Y, rotation.X, rotation.Z) *
                        Matrix.CreateScale(scale) * Matrix.CreateTranslation(position);
        }

        public PhysicsObject getPhysicsObject()
        {
            return physicsObject;
        }

        public ModelObject getModelObject()
        {
            return modelObject;
        }

        public int getChildCount()
        {
            return childrenObjects.Count;
        }

        public GameObject getChild(int indx)
        {
            if (indx > childrenObjects.Count || indx < 0)
                return null;

            return childrenObjects[indx];
        }

        public void addChild(GameObject obj)
        {
            childrenObjects.Add(obj);
        }

        public void removeChild(int indx)
        {
            childrenObjects.RemoveAt(indx);
        }

        public void removeChild(GameObject obj)
        {
            childrenObjects.Remove(obj);
        }

    }
}
